﻿using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using EU.Core.Common;
using EU.Core.Common.AppConfig;
using Microsoft.IdentityModel.Tokens;

namespace EU.Core.AuthHelper.OverWrite;

public class JwtHelper
{

    /// <summary>
    /// 颁发JWT字符串
    /// </summary>
    /// <param name="tokenModel"></param>
    /// <returns></returns>
    public static string IssueJwt(TokenModelJwt tokenModel)
    {
        string iss = AppSettings.app(["Audience", "Issuer"]);
        string aud = AppSettings.app(["Audience", "Audience"]);
        string secret = AppSecretConfig.Audience_Secret_String;

        //var claims = new Claim[] //old
        var claims = new List<Claim>
            {
             /*
             * 特别重要：
               1、这里将用户的部分信息，比如 uid 存到了Claim 中，如果你想知道如何在其他地方将这个 uid从 Token 中取出来，请看下边的SerializeJwt() 方法，或者在整个解决方案，搜索这个方法，看哪里使用了！
               2、你也可以研究下 HttpContext.User.Claims ，具体的你可以看看 Policys/PermissionHandler.cs 类中是如何使用的。
             */

                

            new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ToString()),
            new Claim(JwtRegisteredClaimNames.Iat, $"{DateTime.Now.DateToTimeStamp()}"),
            new Claim(JwtRegisteredClaimNames.Nbf,$"{DateTime.Now.DateToTimeStamp()}") ,
            //这个就是过期时间，目前是过期1000秒，可自定义，注意JWT有自己的缓冲过期时间
            new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddSeconds(1000)).ToUnixTimeSeconds()}"),
            new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(1000).ToString()),
            new Claim(JwtRegisteredClaimNames.Iss,iss),
            new Claim(JwtRegisteredClaimNames.Aud,aud),
            
            //new Claim(ClaimTypes.Role,tokenModel.Role),//为了解决一个用户多个角色(比如：Admin,System)，用下边的方法
           };

        // 可以将一个用户的多个角色全部赋予；
        // 作者：DX 提供技术支持；
        claims.AddRange(tokenModel.Role.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));



        //秘钥 (SymmetricSecurityKey 对安全性的要求，密钥的长度太短会报出异常)
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var jwt = new JwtSecurityToken(
            issuer: iss,
            claims: claims,
            signingCredentials: creds);

        var jwtHandler = new JwtSecurityTokenHandler();
        var encodedJwt = jwtHandler.WriteToken(jwt);

        return encodedJwt;
    }

    /// <summary>
    /// 解析
    /// </summary>
    /// <param name="jwtStr"></param>
    /// <returns></returns>
    public static TokenModelJwt SerializeJwt(string jwtStr)
    {
        var jwtHandler = new JwtSecurityTokenHandler();
        TokenModelJwt tokenModelJwt = new();

        // token校验
        if (jwtStr.IsNotEmptyOrNull() && jwtHandler.CanReadToken(jwtStr))
        {

            JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);

            object role;

            jwtToken.Payload.TryGetValue(ClaimTypes.Role, out role);

            tokenModelJwt = new TokenModelJwt
            {
                Uid = (jwtToken.Id).ObjToLong(),
                Role = role != null ? role.ObjToString() : "",
            };
        }
        return tokenModelJwt;
    }

    public static bool customSafeVerify(string token)
    {
        var jwtHandler = new JwtSecurityTokenHandler();
        var symmetricKeyAsBase64 = AppSecretConfig.Audience_Secret_String;
        var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
        var signingKey = new SymmetricSecurityKey(keyByteArray);
        var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);

        var jwt = jwtHandler.ReadJwtToken(token);
        return jwt.RawSignature == Microsoft.IdentityModel.JsonWebTokens.JwtTokenUtilities.CreateEncodedSignature(jwt.RawHeader + "." + jwt.RawPayload, signingCredentials);
    }
}

/// <summary>
/// 令牌
/// </summary>
public class TokenModelJwt
{
    /// <summary>
    /// Id
    /// </summary>
    public long Uid { get; set; }
    /// <summary>
    /// 角色
    /// </summary>
    public string Role { get; set; }
    /// <summary>
    /// 职能
    /// </summary>
    public string Work { get; set; }

}
